package com.calwen.xsmarthome.util;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson2.JSONObject;
import com.calwen.xsmarthome.bo.ApiResult;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 获取设备ID "/home/device_list" <br>
 * 设置属性uri：/miotspec/prop/set <br>
 * 获取属性uri：/miotspec/prop/get <br>
 * 使用方法uri：/miotspec/action <br>
 */
public class MjUtil {
    private static final Logger logger = LoggerFactory.getLogger(MjUtil.class);
    private static long lastAlterTime;
    private static Map<String, Object> authMap;

    static {
        authMap = getAuth("17607889421", "WHL531222");
    }

    public static void main(String[] args) throws Exception {
        Map<String, Object> authMap = getAuth("17607889421", "WHL531222");
        monitor(authMap);
        setProperty("/miotspec/prop/set", "{\"params\":[{\"did\":\"752588420\",\"siid\":2,\"piid\":2,\"value\":11}]}");
    }


    /**
     * 登录
     */
    public static Map<String, Object> getAuth(String userName, String password) {
        JSONObject data = new JSONObject();
        Map<String, Object> headerMap = getMobileRequestHeader();

        // 1.获取登录参数
        String serviceLoginUrl = "https://account.xiaomi.com/pass/serviceLogin?sid=xiaomiio&_json=true";
        String response = OkHttpUtil.doGet(serviceLoginUrl, null, headerMap);
        JSONObject result = JSONObject.parseObject(response.substring(11));

        // 2.账号密码登录
        Map<String, Object> param = new HashMap<>();
        param.put("qs", result.getString("qs"));
        param.put("sid", result.getString("sid"));
        param.put("_sign", result.getString("_sign"));
        param.put("callback", result.getString("callback"));
        param.put("user", userName);
        param.put("hash", MD5.create().digestHex(password).toUpperCase());
        param.put("_json", "true");
        String serviceLoginAuth2Url = "https://account.xiaomi.com/pass/serviceLoginAuth2";
        response = OkHttpUtil.doPostFormBody(serviceLoginAuth2Url, param, headerMap);
        result = JSONObject.parseObject(response.substring(11));
        if (result.getIntValue("code") != 0) {
            data.put("code", result.getIntValue("code"));
            data.put("message", result.getString("desc"));
            return data;
        }
        String userId = null;
        String securityToken = null;

        try {
            // 3.获取service token
            String nonce = result.getString("nonce");
            String location = result.getString("location");
            userId = result.getString("userId");
            securityToken = result.getString("ssecurity");
            String n = String.format("nonce=%s&%s", nonce, securityToken);
            MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
            messageDigest.update(n.getBytes("utf-8"));
            String url = location + "&clientSign=" + URLEncoder.encode(Base64.getEncoder().encodeToString(messageDigest.digest()), "utf-8");
            try (Response responseData = OkHttpUtil.doGetResponse(url, null, headerMap)) {
                List<Cookie> cookies = Cookie.parseAll(HttpUrl.parse(url), responseData.headers());
                for (Cookie cookie : cookies) {
                    data.put(cookie.name(), cookie.value());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        data.put("userId", userId);
        data.put("securityToken", securityToken);
        data.put("deviceId", RandomUtil.randomString(16));
        data.put("code", 0);
        data.put("message", "登录成功");
        return data;
    }

    /**
     * 模拟手机请求 获取请求头
     */
    public static Map<String, Object> getMobileRequestHeader() {
        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("User-Agent", "APP/com.xiaomi.mihome APPV/6.0.103 iosPassportSDK/3.9.0 iOS/14.4 miHSTS");
        return headerMap;
    }


    /**
     * 监控设备状态，检测离线情况
     */
    public static void monitor(Map<String, Object> authMap) {
        String str = """
                {"getVirtualModel": false, "getHuamiDevices": 0}
                """;
        JSONObject res = setProperty("/home/device_list", str);
        logger.info("Device list: {}", res);

        if (res == null) {
            return;
        }

        ApiResult apiResult = res.toJavaObject(ApiResult.class);
        if (apiResult == null || apiResult.getCode() != 0 || apiResult.getResult().getList().isEmpty()) {
            return;
        }

        ApiResult.Item item = apiResult.getResult().getList().get(1);
        if (!item.isOnline() && (System.currentTimeMillis() - lastAlterTime) > 120 * 60 * 1000) {
            logger.error("设备离线告警");
//            sendAlert();
            lastAlterTime = System.currentTimeMillis();
        }
    }

    /**
     * 发送 API 请求
     */
    public static JSONObject setProperty(String uri, String data) {
        if (authMap == null) {
            authMap = MjUtil.getAuth("17607889421", "WHL531222");
        }
        String serviceToken = String.valueOf(authMap.get("serviceToken"));
        String securityToken = String.valueOf(authMap.get("securityToken"));
        String deviceId = String.valueOf(authMap.get("deviceId"));
        String userId = String.valueOf(authMap.get("userId"));
        if (serviceToken == null) {
            logger.error("请先登录");
            return null;
        }

        try {
            Map<String, Object> header = getMobileRequestHeader();
            header.put("x-xiaomi-protocal-flag-cli", "PROTOCAL-HTTP2");
            header.put("Cookie", "PassportDeviceId=" + deviceId + ";userId=" + userId + ";serviceToken=" + serviceToken + ";");

            String nonce = RandomUtil.randomString(16);
            String signedNonce = generateSignedNonce(securityToken, nonce);
            String signature = generateSignature(uri, signedNonce, nonce, data);

            Map<String, Object> param = new HashMap<>();
            param.put("_nonce", nonce);
            param.put("data", data);
            param.put("signature", signature);
            String s = OkHttpUtil.doPostFormBody("https://api.io.mi.com/app" + uri, param, header);
            return JSONObject.parseObject(s);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成加密的 Nonce
     */
    public static String generateSignedNonce(String secret, String nonce) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(Base64.getDecoder().decode(secret));
        digest.update(Base64.getDecoder().decode(nonce));
        return Base64.getEncoder().encodeToString(digest.digest());
    }

    /**
     * 生成 API 请求签名
     */
    public static String generateSignature(String url, String signedNonce, String nonce, String data) throws Exception {
        Mac hmac = Mac.getInstance("HmacSHA256");
        hmac.init(new SecretKeySpec(Base64.getDecoder().decode(signedNonce), "HmacSHA256"));
        String signData = url + "&" + signedNonce + "&" + nonce + "&data=" + data;
        return Base64.getEncoder().encodeToString(hmac.doFinal(signData.getBytes("utf-8")));
    }
}